var wt = require('./weixin-token');
var rt = require('./redis-token');
var RedisLock = require('./redis-lock').RedisLock;
var logger = require('./logger');

var redis = require("redis");
// var client = redis.createClient(6379, '114.215.114.174', { auth_pass: 'weixin-test' });
var client = redis.createClient(6379, '127.0.0.1');

var rl = new RedisLock(client);

// 面向调用层的token操作
class Token {

    constructor() {
        this.tokenInfo = null;
    }

    // 从微信获取token，返回promise
    async getFromWx() {

        let token = null;
        let lock = await rl.lock();
        if (lock) {
            token = await wt.get();
            if (token) {
                await rt.store(token);
            }
            lock.unlock();
        } else {
            logger.info(`[Token] get lock failed!`);
        }

        return token;
    }

    // 是否token为刷新阶段
    isRefreshRange() {
        let now = Date.now();
        return this.tokenInfo && (now > this.tokenInfo.refreshTime) && (now < this.tokenInfo.expireTime);
    }

    // 是否token为过期阶段
    isExpireRange() {
        let now = Date.now();
        return this.tokenInfo && (now >= this.tokenInfo.expireTime);
    }

    // token获取，返回promise
    async get(forceRedis = false, forecWx = false) {

        logger.debug(`[Token] token get`);

        if (forecWx) { // force refresh from weixin
            let token = await this.getFromWx();
            if (token) {
                this.tokenInfo = token;
            } else {
                this.tokenInfo = await this.getDelay();
            }
        } else {
            // from redis
            if (this.tokenInfo == null || this.isExpireRange() || forceRedis) { // 本地token不存在 or 过期阶段 or 强制获取
                logger.debug(`[Token] redis: 本地token不存在 or 过期阶段`);
                this.tokenInfo = await rt.get();
            } else if (this.isRefreshRange()) { // 刷新阶段
                logger.debug(`[Token] redis: 刷新阶段`);
                rt.get().then(token => {
                    if (token) {
                        this.tokenInfo = token;
                    }
                });
            }

            // from weixin
            if (this.tokenInfo == null || this.isExpireRange()) { // 本地token不存在 or 过期阶段
                logger.debug(`[Token] weixin: 本地token不存在 or 过期阶段`);
                let token = await this.getFromWx();
                if (token) {
                    this.tokenInfo = token;
                } else {
                    this.tokenInfo = await this.getDelay();
                }
            } else if (this.isRefreshRange()) { // 刷新阶段, 触发微信token重新获取
                logger.debug(`[Token] weixin: 刷新阶段`);
                this.getFromWx().then(token => {
                    if (token) {
                        this.tokenInfo = token;
                    }
                });
            }
        }
        return this.tokenInfo;
    }

    // token删除，返回promise
    async del() {
        return await rt.del();
    }

    // token延迟获取，返回promise
    getDelay(t = 3000) { // TODO 延迟调用时间间隔需要调优

        logger.debug(`[Token] get delay >> ${t}`);

        return new Promise((resolve, reject) => {
            setTimeout(() => {
                this.get(true).then((tokenInfo) => {
                    resolve(tokenInfo);
                });
            }, t);
        });
    }

    // 当调用发现api失效时，重试获取token
    async reget(oldToken) {
        // check local cache
        if (oldToken.accessToken !== this.tokenInfo.accessToken) {
            logger.debug(`[Token] local cache token is changed.`);
            return this.tokenInfo;
        }

        // check redis
        this.tokenInfo = await rt.get(true); // 强制从redis刷新token
        if (oldToken.accessToken !== this.tokenInfo.accessToken) {
            logger.debug(`[Token] redis token is changed.`);
            return this.tokenInfo;
        }

        // invoke weixin
        let token = await this.getFromWx();
        if (token) {
            logger.debug(`[Token] got token from weixin.`);
            this.tokenInfo = token;
        } else {
            this.tokenInfo = await this.getDelay(); // 延迟重新调用
        }
        return this.tokenInfo;
    }
}

module.exports = new Token();

var rp = require('request-promise');
let token = new Token();
// token.get().then(tokenInfo => {
//     // logger.debug(tokenInfo);
//     // rp(`https://api.weixin.qq.com/cgi-bin/getcallbackip?access_token=${tokenInfo.accessToken}`).then((data) => logger.debug(data));
// });


let ref = setInterval(() => {
    token.get().then(tokenInfo => {
    	// token.reget(tokenInfo);
        // logger.debug('...............');
        // logger.debug(tokenInfo);
        // rp(`https://api.weixin.qq.com/cgi-bin/getcallbackip?access_token=${tokenInfo.accessToken}`).then((data) => logger.debug(data));
    });
}, 500);


setTimeout(() => {
    clearInterval(ref);

    logger.debug(`Redis get count: ${rt.invokeCount}`);
    logger.debug(`Weixin get count: ${wt.invokeCount}`);
}, 20000);


// token.getDelay();
// token.get().then(tokenInfo => logger.debug(tokenInfo));

// setInterval(() => token.get().then(tokenInfo => logger.debug(tokenInfo)), 1000);


// function a() {
//     return new Promise((resolve, reject) => {
//         // resolve(11);
//         // reject(22);
//         throw new Error(33);
//     });
// }

// async function b() {
//     try {
//         let v = await a();
//         logger.debug(v);
//     } catch (err) {
//         logger.debug('Err: ' + err);
//     } finally {
//     	logger.debug('finally do...');
//     }
// }

// b();
